// Sage Android Client.
// Connect to a Sage server, remotely execute commands and display results.
//
// Copyright (C) 2010, Harald Schilly <harald.schilly@gmail.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

package org.sagemath.android;

import android.os.Parcel;
import android.os.Parcelable;

import java.text.DecimalFormat;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Something to do for the Sage Server.
 * 
 * @author Harald Schilly
 */
final public class Calculation {
  
  final public static int INIT = 0, STARTED = 1, FINISHED = 2;
  
  // for the unique id
  final private static AtomicInteger ID = new AtomicInteger(0);
  
  final private static DecimalFormat decimalSeconds = new DecimalFormat();
  
  static {
    decimalSeconds.applyPattern("0.#### [s]");
  }
  
  // id, starttime and code are defacto final and should be
  // treated as such, but they are not because of the aidl serialization.
  
  private int id;
  
  private int state = Calculation.INIT;
  
  private String result = "";
  
  private long starttime = -1L;
  
  private String code = "";
  
  // it's a convention that there has to be this field called CREATOR.
  final public static Parcelable.Creator<Calculation> CREATOR = new Parcelable.Creator<Calculation>() {
    
    @Override
    final public Calculation createFromParcel(Parcel in) {
      return new Calculation(in);
    }
    
    @Override
    final public Calculation[] newArray(int size) {
      return new Calculation[size];
    }
  };
  
  public Calculation(Parcel in) {
    readFromParcel(in);
  }
  
  /**
   * construct a new Calculation object. It is used to communicate between
   * Server/Client (Background Service) and holds the input, later the output
   * and a unique id. Additionally, it gives you the total time for the
   * calculation and it is planned to include a state.
   */
  public Calculation() {
    id = ID.getAndIncrement();
  }
  
  final void setCode(String code) {
    this.code = code;
  }
  
  final public String getCode() {
    return code;
  }
  
  final public void setResult(String result) {
    this.result = result;
  }
  
  final void setStartTime(long starttime) {
    this.starttime = starttime;
  }
  
  /**
   * AIDL serialization, must match with writeToParcel and used in
   * {@link CalculationListener}
   * 
   * @param in
   */
  final void readFromParcel(Parcel in) {
    id = in.readInt();
    state = in.readInt();
    result = in.readString();
    code = in.readString();
    starttime = in.readLong();
  }
  
  /**
   * AIDL serialization, must match with readFromParcel and used in
   * {@link CalculationListener}
   * 
   * @param reply
   * @param parcelableWriteReturnValue
   */
  final void writeToParcel(Parcel reply, int parcelableWriteReturnValue) {
    reply.writeInt(id);
    reply.writeInt(state);
    reply.writeString(result);
    reply.writeString(code);
    reply.writeLong(starttime);
  }
  
  /**
   * the result of the calculation or ""
   * 
   * @return
   */
  final public String getResult() {
    return result;
  }
  
  /**
   * ID of the calculation
   * 
   * @return unique int
   */
  final public int getId() {
    return id;
  }
  
  /**
   * timespan between start of calculation and now in seconds.
   * 
   * @return timespan in seconds
   */
  final public String getElapsed() {
    double d = System.currentTimeMillis() - starttime;
    return decimalSeconds.format(d / 1000.0);
  }
  
}
